package org.apache.ocean.merge;

import java.net.URL;
import java.util.List;
import java.util.Map;

import org.apache.ocean.ClusterRegistry;
import org.apache.ocean.ClusterUtil;
import org.apache.ocean.CurrentIndexSchema;
import org.apache.ocean.IndexSchema;
import org.apache.ocean.Service;
import org.apache.ocean.TimeoutState;
import org.apache.ocean.name.NameClient;
import org.apache.ocean.name.Node;
import org.apache.ocean.nio.OceanNioHttpClient;

/**
 *
 * @author jasonr
 */
// TODO: have did you mean accept user id, create session id out of this, time difference between queries being a session
public class MergeService implements Service {
  public static final int HTTP_TIMEOUT = 10*1000;
  private MergeConfig mergeConfig;
  private String nodeID;
  private OceanNioHttpClient oceanNioHttpClient;
  private MergeClient mergeClient;
  private MergeNameClient mergeNameClient;
  private String serviceStatus;
  
  static {
    ClusterUtil.loadStatics(); 
  }
  
  public MergeClient getMergeClient() {
  	return mergeClient;
  }
  
  public MergeNameClient getMergeNameClient() {
  	return mergeNameClient;
  }
  
  public class CurrentIndexSchemaHandler implements CurrentIndexSchema {
		public IndexSchema getIndexSchema(TimeoutState timeoutState) throws Exception {
			return mergeNameClient.getIndexSchema(timeoutState);
		}

		public IndexSchema getIndexSchema() throws Exception {
			return mergeNameClient.getIndexSchema(new TimeoutState(1000 * 60 * 2));
		}
	}
  
  public String getServiceStatus() {
  	return serviceStatus;
  }
  
  public MergeService() {
    
  }
  
  public String getID() {
    return nodeID;
  }
  
  public static MergeService getMergeService() throws Exception {
    MergeService mergeService = (MergeService)ClusterRegistry.get("mergeService");
    if (mergeService == null) {
      mergeService = new MergeService();
      ClusterRegistry.put("mergeService", mergeService);
      mergeService.start();
    }
    return mergeService;
  }
  
  public class NameEventHandler extends NameClient.EventListener { 
  	
  }
  
  public class MergeClientHandler implements MergeClient.MergeClientInterface {
  	public void reportReadFailure(String nodeID) {
  		
  	}
  	
  	public CurrentIndexSchema getCurrentIndexSchema() {
  		return new CurrentIndexSchemaHandler();
  	}
  	
  	public List<Node> getAddDocumentNodes(TimeoutState timeoutState) throws Exception {
  		return mergeNameClient.getWriteableNodes(timeoutState);
  	}
  	
  	public Map<String,List<Node>> getReadableCellNodes(TimeoutState timeoutState) throws Exception {
  		return mergeNameClient.getReadableCellNodes(timeoutState);
  	}
  	
  	public Node getUpdateDocumentNode(String cellID, TimeoutState timeoutState) throws Exception {
  		return mergeNameClient.getUpdateDocumentNode(cellID, timeoutState);
  	}
  }
  
  public void start() throws Exception {
  	serviceStatus = Service.STARTING;
    mergeConfig = MergeConfig.loadMergeConfig();
    nodeID = ClusterUtil.loadNodeID(mergeConfig.nodeIDFile);
    List<URL> nameURLs = ClusterUtil.loadURLs(mergeConfig.nameURLsFile);
    mergeNameClient = new MergeNameClient(nodeID, nameURLs, new NameEventHandler());
    oceanNioHttpClient = new OceanNioHttpClient(20);
    mergeClient = new MergeClient(new MergeClientHandler(), oceanNioHttpClient);
    serviceStatus = Service.STARTED;
  }
  
  public void stop() throws Exception {
  	serviceStatus = Service.STOPPING;
  	oceanNioHttpClient.shutdown();
  	mergeNameClient.shutdown();
  	serviceStatus = Service.STOPPED;
  }
}
